#!/bin/bash

# Redis Cluster Production Monitoring Script
# ==========================================

set -e

# Configuration
REDIS_PASSWORD="Redis@2024#Prod"
REDIS_NODES=(
    "173.18.0.11:6379"
    "173.18.0.12:6379"
    "173.18.0.13:6379"
    "173.18.0.14:6379"
    "173.18.0.15:6379"
    "173.18.0.16:6379"
)

# Alert thresholds
MEMORY_WARNING_THRESHOLD=80
MEMORY_CRITICAL_THRESHOLD=90
CONNECTIONS_WARNING_THRESHOLD=8000
CONNECTIONS_CRITICAL_THRESHOLD=9500
LATENCY_WARNING_THRESHOLD=10
LATENCY_CRITICAL_THRESHOLD=50

# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color

# Logging function
log() {
    echo -e "${GREEN}[$(date +'%Y-%m-%d %H:%M:%S')] $1${NC}"
}

warn() {
    echo -e "${YELLOW}[$(date +'%Y-%m-%d %H:%M:%S')] WARNING: $1${NC}"
}

error() {
    echo -e "${RED}[$(date +'%Y-%m-%d %H:%M:%S')] ERROR: $1${NC}"
}

info() {
    echo -e "${BLUE}[$(date +'%Y-%m-%d %H:%M:%S')] INFO: $1${NC}"
}

# Get Redis info
get_redis_info() {
    local node=$1
    local section=$2
    
    redis-cli -h ${node%:*} -p ${node#*:} -a $REDIS_PASSWORD info $section 2>/dev/null || echo ""
}

# Get cluster info
get_cluster_info() {
    local node=$1
    
    redis-cli -h ${node%:*} -p ${node#*:} -a $REDIS_PASSWORD cluster info 2>/dev/null || echo ""
}

# Check node connectivity
check_node_connectivity() {
    local node=$1
    
    if redis-cli -h ${node%:*} -p ${node#*:} -a $REDIS_PASSWORD ping &> /dev/null; then
        return 0
    else
        return 1
    fi
}

# Get memory usage percentage
get_memory_usage() {
    local node=$1
    local info
    
    info=$(get_redis_info $node "memory")
    
    local used_memory=$(echo "$info" | grep "used_memory:" | cut -d: -f2 | tr -d '\r')
    local max_memory=$(echo "$info" | grep "maxmemory:" | cut -d: -f2 | tr -d '\r')
    
    if [ -n "$used_memory" ] && [ -n "$max_memory" ] && [ "$max_memory" != "0" ]; then
        echo "scale=2; $used_memory * 100 / $max_memory" | bc -l 2>/dev/null || echo "0"
    else
        echo "0"
    fi
}

# Get connected clients
get_connected_clients() {
    local node=$1
    local info
    
    info=$(get_redis_info $node "clients")
    
    echo "$info" | grep "connected_clients:" | cut -d: -f2 | tr -d '\r' || echo "0"
}

# Get Redis latency
get_redis_latency() {
    local node=$1
    
    # Use redis-cli --latency to measure latency
    timeout 5 redis-cli -h ${node%:*} -p ${node#*:} -a $REDIS_PASSWORD --latency-history -i 1 2>/dev/null | tail -1 | awk '{print $2}' || echo "0"
}

# Check cluster health
check_cluster_health() {
    local node=${REDIS_NODES[0]}
    local cluster_info
    
    cluster_info=$(get_cluster_info $node)
    
    if [[ $cluster_info == *"cluster_state:ok"* ]]; then
        return 0
    else
        return 1
    fi
}

# Monitor single node
monitor_node() {
    local node=$1
    local node_name="redis-${node%:*}"
    
    echo "=========================================="
    info "Monitoring Node: $node_name ($node)"
    echo "=========================================="
    
    # Check connectivity
    if check_node_connectivity $node; then
        log "✓ Node is reachable"
    else
        error "✗ Node is unreachable"
        return 1
    fi
    
    # Get basic info
    local info=$(get_redis_info $node "server")
    local redis_version=$(echo "$info" | grep "redis_version:" | cut -d: -f2 | tr -d '\r')
    local uptime_in_seconds=$(echo "$info" | grep "uptime_in_seconds:" | cut -d: -f2 | tr -d '\r')
    local uptime_days=$((uptime_in_seconds / 86400))
    
    echo "Version: $redis_version"
    echo "Uptime: ${uptime_days} days"
    
    # Memory usage
    local memory_usage=$(get_memory_usage $node)
    local memory_usage_int=$(echo "$memory_usage" | cut -d. -f1)
    
    printf "Memory Usage: %.2f%% [" "$memory_usage"
    
    if [ $memory_usage_int -ge $MEMORY_CRITICAL_THRESHOLD ]; then
        printf "${RED}CRITICAL${NC}"
    elif [ $memory_usage_int -ge $MEMORY_WARNING_THRESHOLD ]; then
        printf "${YELLOW}WARNING${NC}"
    else
        printf "${GREEN}OK${NC}"
    fi
    
    printf "]\n"
    
    # Connected clients
    local connected_clients=$(get_connected_clients $node)
    
    printf "Connected Clients: %s [" "$connected_clients"
    
    if [ $connected_clients -ge $CONNECTIONS_CRITICAL_THRESHOLD ]; then
        printf "${RED}CRITICAL${NC}"
    elif [ $connected_clients -ge $CONNECTIONS_WARNING_THRESHOLD ]; then
        printf "${YELLOW}WARNING${NC}"
    else
        printf "${GREEN}OK${NC}"
    fi
    
    printf "]\n"
    
    # Latency
    local latency=$(get_redis_latency $node)
    local latency_int=$(echo "$latency" | cut -d. -f1)
    
    printf "Latency: %.2fms [" "$latency"
    
    if [ $latency_int -ge $LATENCY_CRITICAL_THRESHOLD ]; then
        printf "${RED}CRITICAL${NC}"
    elif [ $latency_int -ge $LATENCY_WARNING_THRESHOLD ]; then
        printf "${YELLOW}WARNING${NC}"
    else
        printf "${GREEN}OK${NC}"
    fi
    
    printf "]\n"
    
    # Operations per second
    local stats_info=$(get_redis_info $node "stats")
    local instantaneous_ops_per_sec=$(echo "$stats_info" | grep "instantaneous_ops_per_sec:" | cut -d: -f2 | tr -d '\r')
    echo "Operations/sec: $instantaneous_ops_per_sec"
    
    # Hit rate
    local keyspace_hits=$(echo "$stats_info" | grep "keyspace_hits:" | cut -d: -f2 | tr -d '\r')
    local keyspace_misses=$(echo "$stats_info" | grep "keyspace_misses:" | cut -d: -f2 | tr -d '\r')
    
    if [ -n "$keyspace_hits" ] && [ -n "$keyspace_misses" ] && [ "$((keyspace_hits + keyspace_misses))" -gt 0 ]; then
        local hit_rate=$(echo "scale=2; $keyspace_hits * 100 / ($keyspace_hits + $keyspace_misses)" | bc -l 2>/dev/null || echo "0")
        printf "Hit Rate: %.2f%%\n" "$hit_rate"
    else
        echo "Hit Rate: N/A"
    fi
    
    echo ""
}

# Monitor cluster
monitor_cluster() {
    local node=${REDIS_NODES[0]}
    
    echo "=========================================="
    info "Cluster Overview"
    echo "=========================================="
    
    # Check cluster health
    if check_cluster_health; then
        log "✓ Cluster State: Healthy"
    else
        error "✗ Cluster State: Unhealthy"
    fi
    
    # Get cluster info
    local cluster_info=$(get_cluster_info $node)
    
    local cluster_size=$(echo "$cluster_info" | grep "cluster_size:" | cut -d: -f2 | tr -d '\r')
    local known_nodes=$(echo "$cluster_info" | grep "cluster_known_nodes:" | cut -d: -f2 | tr -d '\r')
    local slots_assigned=$(echo "$cluster_info" | grep "cluster_slots_assigned:" | cut -d: -f2 | tr -d '\r')
    local slots_ok=$(echo "$cluster_info" | grep "cluster_slots_ok:" | cut -d: -f2 | tr -d '\r')
    local slots_pfail=$(echo "$cluster_info" | grep "cluster_slots_pfail:" | cut -d: -f2 | tr -d '\r')
    local slots_fail=$(echo "$cluster_info" | grep "cluster_slots_fail:" | cut -d: -f2 | tr -d '\r')
    
    echo "Cluster Size: $cluster_size nodes"
    echo "Known Nodes: $known_nodes"
    echo "Slots Assigned: $slots_assigned/16384"
    echo "Slots OK: $slots_ok"
    echo "Slots PFAIL: $slots_pfail"
    echo "Slots FAIL: $slots_fail"
    
    # Show cluster nodes
    echo ""
    info "Cluster Nodes Status:"
    redis-cli -h ${node%:*} -p ${node#*:} -a $REDIS_PASSWORD cluster nodes | head -6
    
    echo ""
}

# Generate summary report
generate_summary() {
    local total_nodes=0
    local healthy_nodes=0
    local total_memory_usage=0
    local total_connections=0
    local critical_issues=0
    local warnings=0
    
    echo "=========================================="
    info "Summary Report"
    echo "=========================================="
    
    for node in "${REDIS_NODES[@]}"; do
        ((total_nodes++))
        
        if check_node_connectivity $node; then
            ((healthy_nodes++))
            
            local memory_usage=$(get_memory_usage $node)
            local memory_usage_int=$(echo "$memory_usage" | cut -d. -f1)
            total_memory_usage=$(echo "$total_memory_usage + $memory_usage" | bc -l)
            
            local connections=$(get_connected_clients $node)
            total_connections=$((total_connections + connections))
            
            if [ $memory_usage_int -ge $MEMORY_CRITICAL_THRESHOLD ]; then
                ((critical_issues++))
            elif [ $memory_usage_int -ge $MEMORY_WARNING_THRESHOLD ]; then
                ((warnings++))
            fi
            
            if [ $connections -ge $CONNECTIONS_CRITICAL_THRESHOLD ]; then
                ((critical_issues++))
            elif [ $connections -ge $CONNECTIONS_WARNING_THRESHOLD ]; then
                ((warnings++))
            fi
        else
            ((critical_issues++))
        fi
    done
    
    printf "Total Nodes: %d/%d healthy\n" "$healthy_nodes" "$total_nodes"
    printf "Average Memory Usage: %.2f%%\n" "$(echo "scale=2; $total_memory_usage / $total_nodes" | bc -l)"
    printf "Total Connections: %d\n" "$total_connections"
    
    if [ $critical_issues -gt 0 ]; then
        printf "Critical Issues: ${RED}%d${NC}\n" "$critical_issues"
    fi
    
    if [ $warnings -gt 0 ]; then
        printf "Warnings: ${YELLOW}%d${NC}\n" "$warnings"
    fi
    
    if [ $critical_issues -eq 0 ] && [ $warnings -eq 0 ]; then
        printf "Status: ${GREEN}ALL OK${NC}\n"
    fi
}

# Main execution
main() {
    local mode=${1:-"full"}
    
    case $mode in
        "cluster")
            monitor_cluster
            ;;
        "summary")
            for node in "${REDIS_NODES[@]}"; do
                monitor_node $node
            done
            generate_summary
            ;;
        "full"|*)
            monitor_cluster
            for node in "${REDIS_NODES[@]}"; do
                monitor_node $node
            done
            generate_summary
            ;;
    esac
}

# Show usage
usage() {
    echo "Usage: $0 [mode]"
    echo "Modes:"
    echo "  cluster  - Show cluster overview only"
    echo "  summary  - Show detailed node monitoring with summary"
    echo "  full     - Show complete monitoring (default)"
    echo ""
    echo "Examples:"
    echo "  $0              # Full monitoring"
    echo "  $0 cluster      # Cluster overview only"
    echo "  $0 summary      # Detailed monitoring with summary"
}

# Check arguments
if [ "$1" = "--help" ] || [ "$1" = "-h" ]; then
    usage
    exit 0
fi

# Run main function
main "$@"